package iterator;

import global.GlobalConst;
import global.RID;
import heap.Heapfile;
import heap.Scan;
import heap.Tuple;
import heap.exceptions.InvalidTupleSizeException;

import java.io.IOException;


public class SpoofIbuf implements GlobalConst {

	private byte[][] buffer; 
	private int tupleSize; 
	private int maxPagesAtBuffer; 
	private int maxTuplesAtPage;  
	private Scan hf_scan;  
	private int actualTuplesAtBuffer;
	private int tupleReadFromCurrentPage;
	private int tupleReadFromCurrentuffer;
	private boolean done;
	private int currentPage;  
	private int tuplesAtPageIntheBuffer;
	private int actualTuplesAtPage;
	
	
	/**
	 *constructor, use the init to initialize
	 */
	public SpoofIbuf() {
		hf_scan = null;
	}

	/**
	 *Initialize some necessary inormation, call Iobuf to create the object,
	 * and call init to finish intantiation
	 * 
	 * @param bufs
	 *            [][] the I/O buffer
	 *@param n_pages
	 *            the numbers of page of this buffer
	 *@param tSize
	 *            the tuple size
	 *@param fd
	 *            the reference to an Heapfile
	 *@param Ntuples
	 *            the tuple numbers of the page
	 *@exception IOException
	 *                some I/O fault
	 *@exception Exception
	 *                other exceptions
	 */
	public void init(Heapfile fd, byte bufs[][], int n_pages, int tSize,
			int Ntuples) throws IOException, Exception
	{
		buffer = bufs;
		tupleSize = tSize;
		maxPagesAtBuffer = n_pages;
		actualTuplesAtPage = Ntuples;
		
		actualTuplesAtBuffer=0;
		maxTuplesAtPage = MINIBASE_PAGESIZE / tSize;
		currentPage =0;
		tupleReadFromCurrentPage =0;
		tupleReadFromCurrentuffer =0;
		tuplesAtPageIntheBuffer =0;
		done = false;
		
		if(hf_scan!=null)
			hf_scan = null;
		try
		{
			hf_scan = fd.openScan();
		}catch(Exception e)
		{
			throw e;
		}
	}

	/**
	 *get a tuple from current buffer,pass reference buf to this method
	 * usage:temp_tuple = tuple.Get(buf);
	 * 
	 * @param buf
	 *            write the result to buf
	 *@return the result tuple
	 *@exception IOException
	 *                some I/O fault
	 *@exception Exception
	 *                other exceptions
	 */
	public Tuple Get(Tuple buf) throws IOException, Exception 
	{
		if(tuplesAtPageIntheBuffer == actualTuplesAtPage)
			done = true;
		if(done)
		{
			// All the file is readed Not only the current buffer
			buf = null;
			return  null;
		}
		
		if(tupleReadFromCurrentuffer == actualTuplesAtBuffer)  // All records at the current buffer read but still in the file
		{
			try
			{
				actualTuplesAtBuffer = readin();
			}
			catch(Exception e)
			{
				throw e;
			}
			tupleReadFromCurrentPage =0;
			currentPage =0;
			tupleReadFromCurrentuffer =0;
		}
		
		if(actualTuplesAtBuffer==0) // buffer in empty No more Data At the File
		{
			done =true;
			buf = null;
			return null;
		}
		
		// get the data form the buffer
		buf.tupleSet(buffer[currentPage], tupleReadFromCurrentPage * tupleSize, tupleSize);
		tuplesAtPageIntheBuffer++;
		tupleReadFromCurrentuffer++;
		tupleReadFromCurrentPage++;
		
		if(tupleReadFromCurrentPage == maxTuplesAtPage)
		{
			currentPage++;
			tupleReadFromCurrentPage=0;
		}
	    return buf;
	}

	/**
	 *@return if the buffer is empty,return true. otherwise false
	 */
	public boolean empty() 
	{
		if (tuplesAtPageIntheBuffer == actualTuplesAtPage)
			done = true;
		return done;
	}

	/**
	 * 
	 *@return the numbers of tuples in the buffer
	 *@exception IOException
	 *                some I/O fault
	 *@exception InvalidTupleSizeException
	 *                Heapfile error
	 */
	private int readin() throws IOException, InvalidTupleSizeException {
		int tot_read =0;
		int t_read = 0;
		currentPage =0;
		while(currentPage < maxPagesAtBuffer)
		{
			while(t_read < maxTuplesAtPage)
			{
				RID recored = new RID();
				Tuple tuple = new Tuple ();
				tuple = hf_scan.getNext(recored);
				if(tuple== null)
					return tot_read;
				byte[] data = tuple.getTupleByteArray();
				System.arraycopy(data, 0,buffer[currentPage],t_read*tupleSize,tupleSize);
				t_read++;
				tot_read++;
			}
			t_read =0;
			currentPage++;
		}
		return tot_read;	
	}


}
